package com.yssoft.shiro;

import com.google.common.base.Objects;
import com.yssoft.entity.core.TAccounts;
import com.yssoft.entity.core.TDepartment;
import com.yssoft.entity.core.TEnterprise;
import com.yssoft.entity.core.TPersonnel;
import com.yssoft.framework.Constant;
import com.yssoft.service.core.AccountsService;
import com.yssoft.service.core.DepartmentService;
import com.yssoft.service.core.EnterpriseService;
import com.yssoft.service.core.PersonService;
import com.yssoft.utils.SessionUtil;
import com.yssoft.utils.UserHelper;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Set;


/**
 * 自定义Realm,进行数据源配置
 */
public class MyRealm extends AuthorizingRealm {
    
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
    @Resource
    private AccountsService accountsService;
    @Resource
    private PersonService personService;
    @Resource
    private EnterpriseService enterpriseService;
    @Resource
    private DepartmentService departmentService;

	/**
	 * 只有需要验证权限时才会调用, 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.在配有缓存的情况下，只加载一次.
	 * 如果需要动态权限,但是又不想每次去数据库校验,可以存在ehcache中.自行完善
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
	{
		String loginName = principalCollection.getPrimaryPrincipal().toString();  
		if (loginName != null)
		{
			ShiroUser shiroUser = UserHelper.getCurrentUser();
			Set<String> functions = this.accountsService.queryPermissionForList(shiroUser.id);
				SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
				info.addStringPermissions(functions);
				logger.info(String.format("用户[%s]登录成功,获取权限集合:%s", shiroUser.getLoginName(), functions.toString()));
				return info;
		}
		return null;
	}

	/**
	 * 认证回调函数,登录时调用
	 * 首先根据传入的用户名获取User信息；然后如果user为空，那么抛出没找到帐号异常UnknownAccountException；
	 * 如果user找到但锁定了抛出锁定异常LockedAccountException；最后生成AuthenticationInfo信息，
	 * 交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配，
	 * 如果不匹配将抛出密码错误异常IncorrectCredentialsException；
	 * 另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException；
	 * 在组装SimpleAuthenticationInfo信息时， 需要传入：身份信息（用户名）、凭据（密文密码）、盐（username+salt），
	 * CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。
	 */
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
		String accountName = (String) token.getPrincipal();
        Session session = SecurityUtils.getSubject().getSession();
       
        
        String isPhone = (String)SecurityUtils.getSubject().getSession().getAttribute("isPhone");
        TAccounts user=null;
		if("1".equals(isPhone)){
		    //是手机号登陆
            //当前是手机号
            TPersonnel personnel=personService.queryPersonByPhone(accountName);//如果使用手机号登陆，则使用手机号查询人员
            user = accountsService.queryAccountByPersonId(personnel.getId());//根据人员查询账号
        }else{
		    //账号密码登陆
            user = accountsService.queryAccByLoginName(accountName);
        }
		if (user != null){
            //从数据库查询出来的账号名和密码,与用户输入的账号和密码对比
            //当用户执行登录时,在方法处理上要实现user.login(token);
            //然后会自动进入这个类进行认证
            //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，如果觉得人家的不好可以自定义实
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());
            ShiroUser shiroUser = new ShiroUser();
            try{
                
                shiroUser.setLoginName(user.getLoginName());
                if(user.gettPId() != null) {
                    shiroUser.setEntId(user.gettEId());
                    shiroUser.setId(user.getId());
                    shiroUser.setPersonId(user.gettPId());
                    TPersonnel person = personService.queryPersonById(user.gettPId().toString());
                    if(person!=null) {
                        shiroUser.setPersonId(person.getId());
                        if(person.getName() != null && !"".equals(person.getName())){
                        	shiroUser.setPersonName(person.getName());
                        } else if(person.getPhone() != null &&!"".equals(person.getPhone()) ){
                        	shiroUser.setPersonName(person.getPhone());
                        }else{
                        	shiroUser.setPersonName("");
                        }
                        TDepartment dept = departmentService.queryTDepartmentById(person.gettDId());
                        if(dept!=null) {
                            shiroUser.setDeptId(dept.getId());
                            shiroUser.setDeptName(dept.getName());
                        }
                    }
                    
                }
                TEnterprise ent = enterpriseService.queryEnterpriseById(user.gettEId());
                if(ent!=null){
                    shiroUser.setEntName(ent.getName());
                }
            }catch(Exception e){
                e.printStackTrace();
            }
            session.setAttribute("isLogin", "true");
			SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(shiroUser,user.getPassword(),credentialsSalt, getName());
            //当验证都通过后，把用户信息放在session里
			session.setAttribute(SessionUtil.USER_SESSION_KEY, user);
			session.setAttribute(SessionUtil.USER_SESSION, shiroUser);
			return authenticationInfo;
		} else{
			session.setAttribute("isLogin", "true");
			throw new UnknownAccountException();// 没找到帐号
		}
  
	}

	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(PrincipalCollection principals)
	{
		super.clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 更新用户信息缓存.
	 */
	public void clearCachedAuthenticationInfo(PrincipalCollection principals)
	{
		super.clearCachedAuthenticationInfo(principals);
	}

	/**
	 * 清除用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo()
	{
		getAuthorizationCache().clear();
	}

	/**
	 * 清除用户信息缓存.
	 */
	public void clearAllCachedAuthenticationInfo()
	{
		getAuthenticationCache().clear();
	}

	/**
	 * 清空所有缓存
	 */
	public void clearCache(PrincipalCollection principals)
	{
		super.clearCache(principals);
	}

	/**
	 * 清空所有认证缓存
	 */
	public void clearAllCache()
	{
		clearAllCachedAuthenticationInfo();
		clearAllCachedAuthorizationInfo();
	}
    
    
    /**
     * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
     */
    public static class ShiroUser implements Serializable {
        private static final long serialVersionUID = -1373760761780840081L;
        public Integer id;
        public String loginName;//登陆名
        public String name;//登陆人姓名
        public Integer personId;
        public Integer deptId;
        public String personName;
        public String deptName;
        public Integer entId;//企业id
        public String entName;//企业名称
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getLoginName() {
            return loginName;
        }
    
        public void setLoginName(String loginName) {
            this.loginName = loginName;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getEntId() {
            return entId;
        }
    
        public void setEntId(Integer entId) {
            this.entId = entId;
        }
    
        public String getEntName() {
            return entName;
        }
    
        public void setEntName(String entName) {
            this.entName = entName;
        }
   
        
        public Integer getPersonId() {
			return personId;
		}

		public void setPersonId(Integer personId) {
			this.personId = personId;
		}

		public Integer getDeptId() {
			return deptId;
		}

		public void setDeptId(Integer deptId) {
			this.deptId = deptId;
		}

		public String getPersonName() {
			if(null==personName || "".equals(personName)) {
				personName=Constant.LOGIN_DETFAULT_NAME;
			}
			return personName;
		}

		public void setPersonName(String personName) {
			if(null==personName || "".equals(personName)) {
				personName=Constant.LOGIN_DETFAULT_NAME;;
			}
			this.personName = personName;
		}

		public String getDeptName() {
			return deptName;
		}

		public void setDeptName(String deptName) {
			this.deptName = deptName;
		}

		/**
         * 本函数输出将作为默认的<shiro:principal/>输出.
         */
        @Override
        public String toString() {
            return loginName;
        }
        
        /**
         * 重载hashCode,只计算loginName;
         */
        @Override
        public int hashCode() {
            return Objects.hashCode(loginName);
        }
        
        /**
         * 重载equals,只计算loginName;
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            ShiroUser other = (ShiroUser) obj;
            if (loginName == null) {
                if (other.loginName != null) {
                    return false;
                }
            } else if (!loginName.equals(other.loginName)) {
                return false;
            }
            
            return true;
        }
        
    }
	
	
}